#pragma once
#include<iostream>
#include<assert.h>
using namespace std;



template<class T>
class Vector
{
public:
	typedef T* iterator;
	typedef const T* const_iterator;

	iterator begin()
	{
		return _start;
	}

	iterator end()
	{
		return _finish;
	}

	const_iterator cbegin() const
	{
		return _start;
	}

	const_iterator cend() const
	{
		return _finish;
	}



	// construct and destroy
	Vector()
	{}

	Vector(size_t n, const T& val = T())
	{
		reserve(n);
		for (size_t i = 0; i < n; i++)
		{
			push_back(val);
		}
	}

	Vector(int n, const T& val = T())
	{
		reserve(n);
		for (size_t i = 0; i < n; i++)
		{
			push_back(val);
		}
	}

	/*template<typename input_iterator>
	Vecrot(input_iterator first, input_iterator last)
	{
		while (first != last)
		{
			push_back(*first);
			first++;
		}
	}*/

	Vector(const Vector<T>& v)
	{
		reserve(v.capacity());

		for (auto& t : v)
		{
			push_back(t);
		}
	}

	Vector<T>& operator= (Vector<T> v)
	{
		swap(v);

		return *this;
	}

	~Vector()
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}
	}



	// capacity
	size_t size() const
	{
		return _finish - _start;
	}

	size_t capacity() const
	{
		return _end_of_storage - _start;
	}

	void reserve(size_t n)
	{
		if (n > capacity())
		{
			size_t sz = size();

			T* new_start = new T[n];
			if(_start)
			{
				for (size_t i = 0; i < sz; i++)
				{
					new_start[i] = _start[i];
				}

				delete[] _start;
			}

			_start = new_start;
			_finish = _start + sz;
			_end_of_storage = _start + n;
		}
	}

	void resize(size_t n, const T& val = T())
	{
		if (n <= size())
		{
			_finish = _start + n;
		}
		else
		{
			reserve(n);

			while (_finish != _start + n)
			{
				*_finish = val;
				_finish++;
			}
		}
	}



	// access
	T& operator[](size_t pos)
	{
		assert(pos < size());

		return _start[pos];
	}

	const T& operator[](size_t pos) const
	{
		assert(pos < size());

		return _start[pos];
	}



	// modify
	void push_back(const T& val)
	{
		if (size() == capacity())
		{
			reserve(capacity() == 0 ? 4 : 2 * capacity());
		}

		*(_finish++) = val;
	}

	void pop_back()
	{
		assert(size() > 0);

		_finish--;
	}
		
	void swap(Vector<T>& v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_end_of_storage, v._end_of_storage);
	}

	iterator insert(iterator pos, const T& val)
	{
		assert(pos >= begin());
		assert(pos <= end());

		if (size() == capacity())
		{
			size_t len = pos - _start;
			reserve(capacity() == 0 ? 4 : 2 * capacity());
			pos = _start + len;
		}

		iterator End = _finish - 1;
		while (End >= pos)
		{
			*(End + 1) = *End;
		}
		*pos = val;
		_finish++;

		return pos;
	}

	iterator erase(iterator pos)
	{
		assert(pos >= begin());
		assert(pos < end());

		iterator Begin = pos + 1;
		while (Begin < _finish)
		{
			*(Begin - 1) = *Begin;
		}
		_finish--;

		return pos;
	}

private:
	iterator _start = nullptr;
	iterator _finish = nullptr;
	iterator _end_of_storage = nullptr;
};